﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using DynamicDnsChanger.Extensions;
using DynamicDnsChanger.Extensions.Requester;
namespace DynamicDnsChanger.MEF
{
    class PluginLoader
    { }
    class GenericPluginLoader<T> : IDisposable
    {
        private CompositionContainer _Container;
        [ImportMany]
        public IEnumerable<T> Plugins
        {
            get;
            set;
        }
        //[Import]
        //public T Plugin
        //{
        //    get;
        //    set;
        //}
        //[Export]
        //ILog _Log;
        [Export]
        IRequester _Requester;
        

        public GenericPluginLoader(string path)
            : this(path, null)
        {
            //Log.Info("GenericPluginLoader(string path, ILog Log)");
        }

        public GenericPluginLoader
            (
                string path,
            IRequester Requester
            )
        {
            this._Requester = Requester;
            if (!Directory.Exists(path))
            {
                //_Log.Info(String.Format("Diretório não localizado: {0}", path));
                return;
            }
            //_Log.Info(String.Format("Procurando por plugins válidos em: {0}", path));

            DirectoryCatalog directoryCatalog = new DirectoryCatalog(path);
            byte[] trustedKey = typeof(PluginLoader).Assembly.GetName().GetPublicKey();
            //An aggregate catalog that combines multiple catalogs
            //var catalog = new AggregateCatalog(directoryCatalog);
            var catalog = new AggregateCatalog();
            //Verificar a assinatura dos plugins: http://blogs.msdn.com/b/dsplaisted/archive/2010/11/01/how-to-control-who-can-write-extensions-for-your-mef-application.aspx
            foreach (var file in Directory.GetFiles(path))
            {
                AssemblyName assemblyName = null;
                try
                {
                    assemblyName = AssemblyName.GetAssemblyName(file);
                }
                catch (ArgumentException)
                {
                    //  According to MSDN, ArgumentException can be thrown if the assembly file is invalid
                }
                catch (BadImageFormatException)
                {
                    //  Not a valid assembly
                }

                if (assemblyName != null)
                {
                    #region Não verificar assinatura por enquanto
                    //var publicKey = assemblyName.GetPublicKey();
                    //if (publicKey != null)
                    //{
                    //    bool trusted = assemblyName.GetPublicKey().SequenceEqual(trustedKey);
                    //    if (trusted)
                    //    {
                    //        _Log.Info(String.Format("Carregando assembly: {0}", assemblyName.Name));

                    //        catalog.Catalogs.Add(new AssemblyCatalog(file));
                    //    }
                    //    else
                    //    {
                    //        _Log.Info(String.Format("Assembly não esta assinado com a chave esperada: {0}", assemblyName.Name));
                    //    }
                    //} 
                    #endregion
                    catalog.Catalogs.Add(new AssemblyCatalog(file));
                }
            }

            // Create the CompositionContainer with all parts in the catalog (links Exports and Imports)

            try
            {
                _Container = new CompositionContainer(catalog);
                //Fill the imports of this object
                _Container.ComposeParts(this);
            }

            catch (Exception ex)
            {
                if (ex is System.Reflection.ReflectionTypeLoadException)
                {
                    var typeLoadException = ex as ReflectionTypeLoadException;
                    var loaderExceptions = typeLoadException.LoaderExceptions;
                    loaderExceptions.ToList()
                        .ForEach(x => Console.WriteLine("GenericPluginLoader::LoaderException>> " + x.Message));
                        //.ForEach(x => _Log.Error("GenericPluginLoader::LoaderException>> " + x.Message));
                    return;
                }
                //_Log.Error("GenericPluginLoader>> " + ex.Message);
                if (null != ex.InnerException)
                {
                    //_Log.Error("GenericPluginLoader::InnerException>> " + ex.InnerException.Message);
                }
            }

        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        ~GenericPluginLoader()
        {
            Dispose(false);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                this._Requester = null;                
            }
        }
    }
}
